package com.dingreading.cloud.common.util.aliyun;


import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.Credentials;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentials;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.*;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;

import com.dingreading.cloud.common.util.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.multipart.MultipartFile;

import javax.net.ssl.X509TrustManager;
import java.io.*;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;


/**
 * 阿里云 OSS工具类
 */
public class MstOSSClientUtil {
    public static final Logger logger = LoggerFactory.getLogger(OSSClientUtil.class);

    // 从STS服务获取的安全令牌
    public static final String STS_SECURITYTOKEN = "sts_securityToken";
    // 从STS服务获取的accessKeyId
    public static final String STS_ACCESSKEYID = "sts_accessKeyId";
    // 从STS服务获取的accessKeySecret
    public static final String STS_ACCESSKEYSECRET = "sts_accessKeySecret";
    // sts服务获取的过期时间
    public static final String STS_EXPIRATION = "sts_expiration";

    /**
     * 防盗bucket，读写权限私有
     */
    public static String privateBucket_subject = "mst-subject";

    /**
     * 公共bucket
     */
    public static String publicBucket = "mst-cloud";

    /**
     * 课节视频bucket
     */
    public static String classVideoBucket = "mst-class";

    // region
    public static final String region = "oss-cn-shanghai";

    // endpoint
    public static final String endpoint = "https://oss-cn-shanghai.aliyuncs.com";

    // accessKey
    private static final String accessKeyId = "LTAI5tRMnzGcAMEwsaMSNhFd";
    private static final String accessKeySecret = "doDNKa8aGEwQXXhxbolsomDAYnhNH5";

    // 书籍图片
    public static final String bookImg = "bookImg/";
    // 结算分成文件路径
    public static final String royaltyFile = "royaltyfile/";
    // 课节视频路径
    public static final String record = "record/";

    // RAM角色ARN
    public static final String roleArn = "acs:ram::1222336231948697:role/ramoss";
    // 角色会话名称
    public static final String roleName = "RamOss";


    private static OSS ossClient;

    public void initOss() {
        ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    }


    /**
     * 销毁
     */
    public void destory() {
        //单例不销毁
        ossClient.shutdown();
    }

    /**
     * 获取当天的上传路径
     *
     * @param dir
     */
    public String getTodayDir(String dir) {
        return dir.concat(DateUtil.nowToDateFullDate()).concat("/");
    }

    /**
     * 获取当天日期分割后的上传路径
     *
     * @param dir
     */
    public String getTodaySplitDir(String dir) {
        String nowDateStr = DateUtil.getNowDateStr();
        String[] split = StringUtils.split(nowDateStr, "-");
        // linux文件路径
        String ymd = split[0] + "/" + split[1] + "/" + split[2] + "/";
        return dir + ymd;
    }

    /**
     * 获取阿里云上传的文件名
     *
     * @param file
     */
    public String getFileName(MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        String substring = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
        String name = UUID.randomUUID().toString().toUpperCase().replace("-", "") + substring;
        try {
            return name;
        } catch (Exception e) {
            System.out.println("获取阿里云上传的文件名");
        }
        return "";
    }

    /**
     * 随机获取叮叮学院视频文件名
     */
    public String getCourseVideoFileName(String fileType) {
        String name = UUID.randomUUID().toString().toUpperCase().replace("-", "") + "." + fileType;
        try {
            return name;
        } catch (Exception e) {
            System.out.println("获取阿里云上传的文件名失败");
        }
        return "";
    }

    /**
     * 文件上传
     *
     * @param file
     */
    public String uploadImg2Oss(String dir, MultipartFile file) {
        String originalFilename = file.getOriginalFilename();
        String substring = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
        String name = UUID.randomUUID().toString().toUpperCase().replace("-", "") + substring;
        try {
            InputStream inputStream = file.getInputStream();
            uploadFile2OSS(inputStream, dir, name);
        } catch (Exception e) {
            System.out.println("文件上传失败");
            return "";
        }
        return name;
    }

    public String uploadImg2Oss(String dir, InputStream inputStream, String originalFilename) {
        String substring = originalFilename.substring(originalFilename.lastIndexOf(".")).toLowerCase();
        String name = UUID.randomUUID().toString().toUpperCase().replace("-", "") + substring;
        try {
            uploadFile2OSS(inputStream, dir, name);
        } catch (Exception e) {
            System.out.println("文件上传失败");
            return "";
        }
        return name;
    }

    /**
     * 上传到OSS服务器 如果同名文件会覆盖服务器上的
     *
     * @param instream 文件流
     * @param fileName 文件名称 包括后缀名
     * @return 出错返回"" ,唯一MD5数字签名
     */
    public String uploadFile2OSS(InputStream instream, String dir, String fileName) {
        String ret = "";
        try {
            // 创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(instream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf(".") + 1)));//+1取最后小数点后面的文件类型，不含小数点
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            // 上传文件
            PutObjectResult putResult = ossClient.putObject(publicBucket, dir + fileName, instream, objectMetadata);
            System.out.println("putResult = " + putResult.getRequestId());
            System.out.println("putResult = " + putResult.getVersionId());
            System.out.println("putResult = " + putResult.getETag());
            ret = putResult.getETag();
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        } finally {
            try {
                if (instream != null) {
                    instream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ret;
    }

    /**
     * Description: 判断OSS服务文件上传时文件的contentType
     * <p>
     * 文件后缀
     *
     * @return String
     */
    public String getContentType(String filenameExtension) {
        if (filenameExtension.equalsIgnoreCase("bmp")) {
            return "image/bmp";
        }
        if (filenameExtension.equalsIgnoreCase("gif")) {
//            return "image/gif";
            return "image/jpg";
        }
        if (filenameExtension.equalsIgnoreCase("jpeg") || filenameExtension.equalsIgnoreCase("jpg")
                || filenameExtension.equalsIgnoreCase("png")) {
//            return "image/jpeg";
            return "image/jpg";
        }
        if (filenameExtension.equalsIgnoreCase("html")) {
            return "text/html";
        }
        if (filenameExtension.equalsIgnoreCase("txt")) {
            return "text/plain";
        }
        if (filenameExtension.equalsIgnoreCase("vsd")) {
            return "application/vnd.visio";
        }
        if (filenameExtension.equalsIgnoreCase("pptx") || filenameExtension.equalsIgnoreCase("ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (filenameExtension.equalsIgnoreCase("docx") || filenameExtension.equalsIgnoreCase("doc")) {
            return "application/msword";
        }
        if (filenameExtension.equalsIgnoreCase("xml")) {
            return "text/xml";
        }
        if (filenameExtension.equalsIgnoreCase("pdf") || filenameExtension.equalsIgnoreCase("PDF")) {
            return "application/pdf";
        }
        if (filenameExtension.equalsIgnoreCase("mp4") || filenameExtension.equalsIgnoreCase("MP4")) {
            return "video/mpeg4";
        }
        if (filenameExtension.equalsIgnoreCase("rar") || filenameExtension.equalsIgnoreCase("RAR")) {
            return "application/vnd.rar";
        }
//        return "image/jpeg";
        return "image/jpg";
    }

    /**
     * 证书信任管理器类
     */
    public static class X509TrustUtil implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }

        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }

    }

    /**
     * 获取根目录下所有文件大小
     *
     * @return long
     */
    public static Long getOss() {
        try {
            long sizeTotal = 0L;
            ObjectListing objectListing = null;
            do {
                // 每次列举1000个文件或目录。
                ListObjectsRequest request = new ListObjectsRequest(publicBucket).withDelimiter("/").withMaxKeys(1000);
                if (objectListing != null) {
                    request.setMarker(objectListing.getNextMarker());
                }
                objectListing = ossClient.listObjects(request);
                //获取当前文件夹下所有子目录大小
                List<String> folders = objectListing.getCommonPrefixes();
                for (String folder : folders) {
                    sizeTotal = calculateFolderLength(folder) + sizeTotal;
                }

                //获取当前文件夹下所有文件大小
                List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
                if (sums.size() == 0) {
                    continue;
                }
                for (OSSObjectSummary s : sums) {
                    sizeTotal = sizeTotal + s.getSize();
                }

            } while (objectListing.isTruncated());
            //转换为TB
            sizeTotal = sizeTotal / 1024 / 1024 / 1024 / 1024;
//            log.info(" 文件夹下所有子目录大小 : [{}] TB",sizeTotal);
            return sizeTotal;
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * 获取指定文件夹大小
     *
     * @return long
     */
    public static long calculateFolderLength(String folder) {
        long size = 0L;
        ObjectListing objectListing = null;
        do {
            // MaxKey默认值为100，最大值为1000。
            ListObjectsRequest request = new ListObjectsRequest(publicBucket).withPrefix(folder).withMaxKeys(1000);
            if (objectListing != null) {
                request.setMarker(objectListing.getNextMarker());
            }
            objectListing = ossClient.listObjects(request);
            List<OSSObjectSummary> sums = objectListing.getObjectSummaries();
            for (OSSObjectSummary s : sums) {
                size += s.getSize();
            }
        } while (objectListing.isTruncated());
        return size;
    }

    /**
     * 使用STS获取临时访问凭证
     */
    public AssumeRoleResponse.Credentials getAssumeRoleResponse() {
        // durationSeconds token的有效时长，最短15分钟，最长1小时
        long durationSeconds = 3600L;
        // STS接入地址，例如sts.cn-hangzhou.aliyuncs.com。
        String endpoint = "sts.cn-shanghai.aliyuncs.com";
        // 以下Policy用于限制仅允许使用临时访问凭证向目标存储空间examplebucket上传文件。
        // 临时访问凭证最后获得的权限是步骤4设置的角色权限和该Policy设置权限的交集，即仅允许将文件上传至目标存储空间examplebucket下的exampledir目录。
//        String policy = "{\n" +
//                "    \"Version\": \"1\", \n" +
//                "    \"Statement\": [\n" +
//                "        {\n" +
//                "            \"Action\": [\n" +
//                "                \"oss:PutObject\"\n" +
//                "            ], \n" +
//                "            \"Resource\": [\n" +
//                "                \"acs:oss:*:*:dingreading/*\" \n" +
//                "            ], \n" +
//                "            \"Effect\": \"Allow\"\n" +
//                "        }\n" +
//                "    ]\n" +
//                "}";
        try {
            // regionId表示RAM的地域ID。以华东1（杭州）地域为例，regionID填写为cn-hangzhou。也可以保留默认值，默认值为空字符串（""）。
            String regionId = "";
            // 添加endpoint。适用于Java SDK 3.12.0及以上版本。
            DefaultProfile.addEndpoint(regionId, "Sts", endpoint);
            // 添加endpoint。适用于Java SDK 3.12.0以下版本。
            // DefaultProfile.addEndpoint("",regionId, "Sts", endpoint);
            // 构造default profile。
            IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
            // 构造client。
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            // 适用于Java SDK 3.12.0及以上版本。
            request.setSysMethod(MethodType.POST);
            // 适用于Java SDK 3.12.0以下版本。
            //request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleName);
//            request.setPolicy(policy); // 如果policy为空，则用户将获得该角色下所有权限。
            request.setDurationSeconds(durationSeconds); // 设置临时访问凭证的有效时间为3600秒。

            AssumeRoleResponse response = client.getAcsResponse(request);
            if (response == null) return null;
            AssumeRoleResponse.Credentials credentials = response.getCredentials();
            if (credentials == null) return null;
//            System.out.println("Expiration: " + response.getCredentials().getExpiration());
//            System.out.println("Access Key Id: " + response.getCredentials().getAccessKeyId());
//            System.out.println("Access Key Secret: " + response.getCredentials().getAccessKeySecret());
//            System.out.println("Security Token: " + response.getCredentials().getSecurityToken());
//            System.out.println("RequestId: " + response.getRequestId());

            // redis保存半小时
//            ossClientUtil.redisService.set(OSSClientUtil.STS_SECURITYTOKEN, credentials.getSecurityToken(), 1800);
//            ossClientUtil.redisService.set(OSSClientUtil.STS_ACCESSKEYID, credentials.getAccessKeyId(), 1800);
//            ossClientUtil.redisService.set(OSSClientUtil.STS_ACCESSKEYSECRET, credentials.getAccessKeySecret(), 1800);
//            ossClientUtil.redisService.set(OSSClientUtil.STS_EXPIRATION, credentials.getExpiration(), 1800);
            return credentials;
        } catch (ClientException e) {
            System.out.println("获取阿里云STS授权失败：");
            System.out.println("Error code: " + e.getErrorCode());
            System.out.println("Error message: " + e.getErrorMessage());
            System.out.println("RequestId: " + e.getRequestId());
        } catch (com.aliyuncs.exceptions.ClientException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 使用临时访问凭证上传文件至OSS
     *
     * @param securityToken   从STS服务获取的安全令牌
     * @param accessKeyId     从STS服务获取的accessKeyId
     * @param accessKeySecret 从STS服务获取的accessKeySecret
     */
    public void uploadStsFile(String securityToken, String accessKeyId, String accessKeySecret, InputStream inputStream, String dir, String fileName) {
        // 填写步骤五获取的临时访问密钥（AccessKey ID和AccessKey Secret）。
        String objectName = dir + fileName;
        try {
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(inputStream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf(".") + 1)));//+1取最后小数点后面的文件类型，不含小数点
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            // 将本地文件exampletest.txt上传至目标存储空间examplebucket下的目录exampledir。
            PutObjectRequest putObjectRequest = new PutObjectRequest(privateBucket_subject, objectName, inputStream, objectMetadata);
            ossClient.putObject(putObjectRequest);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 使用临时访问凭证上传文件至OSS，带进度条
     *
     * @param securityToken   从STS服务获取的安全令牌
     * @param accessKeyId     从STS服务获取的accessKeyId
     * @param accessKeySecret 从STS服务获取的accessKeySecret
     */
    @Async("MyPoolTaskExecutor")
    public void uploadStsFile(String bucket, String securityToken, String accessKeyId, String accessKeySecret, InputStream inputStream,
                              String dir, String fileName, GetObjectProgressListener progressListener) {
        // 填写步骤五获取的临时访问密钥（AccessKey ID和AccessKey Secret）。
        String objectName = dir + fileName;
        try {
            // 创建OSSClient实例。
            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(inputStream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            objectMetadata.setContentType(getContentType(fileName.substring(fileName.lastIndexOf(".") + 1)));//+1取最后小数点后面的文件类型，不含小数点
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            // 将本地文件exampletest.txt上传至目标存储空间examplebucket下的目录exampledir。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, objectName, inputStream, objectMetadata);
            // 上传文件带进度条
            ossClient.putObject(putObjectRequest.withProgressListener(progressListener));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 使用签名URL进行临时授权访问文件
     *
     * @param securityToken   从STS服务获取的安全令牌
     * @param accessKeyId     从STS服务获取的accessKeyId
     * @param accessKeySecret 从STS服务获取的accessKeySecret
     * @param objectName      填写Object完整路径，例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
     */
    public String getStsFile(String securityToken, String accessKeyId, String accessKeySecret, String objectName) {
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        // 从STS服务获取临时访问凭证后，您可以通过临时访问密钥和安全令牌生成OSSClient。
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);

        String fileUrl = "";
        try {
            // 设置签名URL过期时间，单位为毫秒。
            Date expiration = new Date(new Date().getTime() + 3600 * 1000);
            // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
            URL url = ossClient.generatePresignedUrl(privateBucket_subject, objectName, expiration);
            fileUrl = url.toString();
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return fileUrl;
    }

    /**
     * 使用签名URL进行临时授权访问文件
     *
     * @param securityToken   从STS服务获取的安全令牌
     * @param accessKeyId     从STS服务获取的accessKeyId
     * @param accessKeySecret 从STS服务获取的accessKeySecret
     * @param objectName      填写Object完整路径，例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
     */
    public String getStsFile(String bucketName, String securityToken, String accessKeyId, String accessKeySecret, String objectName) {
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        // 从STS服务获取临时访问凭证后，您可以通过临时访问密钥和安全令牌生成OSSClient。
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);

        String fileUrl = "";
        try {
            // 设置签名URL过期时间，单位为毫秒。
            Date expiration = new Date(new Date().getTime() + 3600 * 1000);
            // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
            URL url = ossClient.generatePresignedUrl(bucketName, objectName, expiration);
            fileUrl = url.toString();
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return fileUrl;
    }

    /**
     * 临时授权复制文件
     *
     * @param securityToken   从STS服务获取的安全令牌
     * @param accessKeyId     从STS服务获取的accessKeyId
     * @param accessKeySecret 从STS服务获取的accessKeySecret
     * @param sourceKey       wtqjls/20231014/23隋上.mp4
     * @param destinationKey  wtqjls/20231014/23.mp4
     */
    public void copyStsFile(String securityToken, String accessKeyId, String accessKeySecret, String sourceKey, String destinationKey) {
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        // 从STS服务获取临时访问凭证后，您可以通过临时访问密钥和安全令牌生成OSSClient。

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);

        try {
            // 将examplebucket下的srcobject.txt拷贝至同一Bucket下的destobject.txt。
            ossClient.copyObject(privateBucket_subject, sourceKey, privateBucket_subject, destinationKey);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 使用签名URL进行临时授权删除文件
     *
     * @param securityToken   从STS服务获取的安全令牌
     * @param accessKeyId     从STS服务获取的accessKeyId
     * @param accessKeySecret 从STS服务获取的accessKeySecret
     */
    public void deleteStsFile(String securityToken, String accessKeyId, String accessKeySecret, String sourceKey) {
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        // 从STS服务获取临时访问凭证后，您可以通过临时访问密钥和安全令牌生成OSSClient。

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);

        try {
            // 将examplebucket下的srcobject.txt拷贝至同一Bucket下的destobject.txt。
            ossClient.deleteObject(privateBucket_subject, sourceKey);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 复制文件
     *
     * @param sourceKey      image/first.mp4
     * @param destinationKey image/copy.mp4
     */
    public void copyFile(String sourceKey, String destinationKey) {
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        // 从STS服务获取临时访问凭证后，您可以通过临时访问密钥和安全令牌生成OSSClient。

        try {
            // 将examplebucket下的srcobject.txt拷贝至同一Bucket下的destobject.txt。
            ossClient.copyObject(publicBucket, sourceKey, publicBucket, destinationKey);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 删除文件
     */
    public void deleteFile(String bucketName, String sourceKey) {
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        // 从STS服务获取临时访问凭证后，您可以通过临时访问密钥和安全令牌生成OSSClient。

        try {
            // 将examplebucket下的srcobject.txt拷贝至同一Bucket下的destobject.txt。
            ossClient.deleteObject(bucketName, sourceKey);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 删除多个文件
     */
    public void deleteFiles(String bucketName, List<String> sourceKeys) {
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        // 从STS服务获取临时访问凭证后，您可以通过临时访问密钥和安全令牌生成OSSClient。

        try {
            // 将examplebucket下的srcobject.txt拷贝至同一Bucket下的destobject.txt。
            // 删除请求
            DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest(bucketName);
            // 赋值需要删除的文件
            deleteRequest.setKeys(sourceKeys);
            //deleteRequest.setEncodingType(URL_ENCODING);
            // 调用删除
            DeleteObjectsResult deleteObjectsResult = ossClient.deleteObjects(deleteRequest);
            // 获取删除的文件
//            List<String> deletedObjects = deleteObjectsResult.getDeletedObjects();
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 使用签名URL进行临时授权访问文件
     *
     * @param securityToken   从STS服务获取的安全令牌
     * @param accessKeyId     从STS服务获取的accessKeyId
     * @param accessKeySecret 从STS服务获取的accessKeySecret
     * @param objectName      填写Object完整路径，例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
     */
    public String getStsFileByBucket(String privateBucket, String securityToken, String accessKeyId, String accessKeySecret, String objectName) {
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        // 从STS服务获取临时访问凭证后，您可以通过临时访问密钥和安全令牌生成OSSClient。

//        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
//        // 私有云要关闭CNAME
//        conf.setSupportCname(false);
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);

        String fileUrl = "";
        try {
            // 设置签名URL过期时间，单位为毫秒。
            Date expiration = new Date(new Date().getTime() + 3600 * 1000);
            // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
            URL url = ossClient.generatePresignedUrl(privateBucket, objectName, expiration);
            fileUrl = url.toString();
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return fileUrl;
    }

    /**
     * 使用签名URL进行临时授权访问多个文件
     *
     * @param securityToken   从STS服务获取的安全令牌
     * @param accessKeyId     从STS服务获取的accessKeyId
     * @param accessKeySecret 从STS服务获取的accessKeySecret
     * @param objectNameList  填写Object完整路径，例如exampleobject.txt。Object完整路径中不能包含Bucket名称。
     */
    public List<String> getStsFileList(String securityToken, String accessKeyId, String accessKeySecret, List<String> objectNameList) {
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        // 从STS服务获取临时访问凭证后，您可以通过临时访问密钥和安全令牌生成OSSClient。
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, securityToken);

        List<String> urlList = new ArrayList<>();
        try {
            // 设置签名URL过期时间，单位为毫秒。
            Date expiration = new Date(new Date().getTime() + 3600 * 1000);
            // 生成以GET方法访问的签名URL，访客可以直接通过浏览器访问相关内容。
            for (int i = 0; i < objectNameList.size(); i++) {
                URL url = ossClient.generatePresignedUrl(privateBucket_subject, objectNameList.get(i), expiration);
                urlList.add(url.toString());
            }
            // 打印签名URL。
            for (String url : urlList) {
                System.out.println(url);
            }
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return urlList;
    }

    /**
     * 判断文件是否存在
     *
     * @param BucketName
     * @param ObjectName
     * @return
     */
    public boolean judgeObjectExist(String BucketName, String ObjectName) {
        boolean b = ossClient.doesObjectExist(BucketName, ObjectName);
        return b;
    }

    /**
     * 下载文件
     */
    public void downloadOssFile(String ossFileUrl) throws Exception {
        // 保存路径
        String pathUrl = "/home/courseData";
        // 保存路径+文件名
        String newFileName = pathUrl;

        String[] urls = ossFileUrl.split("/");
        for (String url : urls) {
            if (!url.contains("."))
                pathUrl += "/" + url;
            newFileName += "/" + url;
        }
        // 创建文件夹
        File file = new File(pathUrl);
        file.mkdirs();

        // 判断文件是否已下载
        File newFile = new File(newFileName);
        if (!newFile.exists()) {
            // 创建OSSClient实例。
            try {
                // 请求10个任务并发下载。
                DownloadFileRequest downloadFileRequest = new DownloadFileRequest(privateBucket_subject, ossFileUrl);
                // 指定Object下载到本地文件的完整路径，例如D:\\localpath\\examplefile.txt。
                downloadFileRequest.setDownloadFile(newFileName);
                // 设置分片大小，单位为字节，取值范围为100 KB~5 GB。默认值为100 KB。
                downloadFileRequest.setPartSize(1 * 1024 * 1024);
                // 设置分片下载的并发数，默认值为1。
                downloadFileRequest.setTaskNum(10);
                // 开启断点续传下载，默认关闭。
                downloadFileRequest.setEnableCheckpoint(true);
                // 设置断点记录文件的完整路径，例如D:\\localpath\\examplefile.txt.dcp。
                // 只有当Object下载中断产生了断点记录文件后，如果需要继续下载该Object，才需要设置对应的断点记录文件。下载完成后，该文件会被删除。
                //downloadFileRequest.setCheckpointFile("D:\\localpath\\examplefile.txt.dcp");

                // 下载文件。
                DownloadFileResult downloadRes = null;
                try {
                    downloadRes = ossClient.downloadFile(downloadFileRequest);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
                // 下载成功时，会返回文件元信息。
                ObjectMetadata objectMetadata = downloadRes.getObjectMetadata();
                System.out.println(objectMetadata.getETag());
                System.out.println(objectMetadata.getLastModified());
                System.out.println(objectMetadata.getUserMetadata().get("meta"));
            } catch (OSSException oe) {
                System.out.println("Caught an OSSException, which means your request made it to OSS, "
                        + "but was rejected with an error response for some reason.");
                System.out.println("Error Message:" + oe.getErrorMessage());
                System.out.println("Error Code:" + oe.getErrorCode());
                System.out.println("Request ID:" + oe.getRequestId());
                System.out.println("Host ID:" + oe.getHostId());
            } catch (ClientException ce) {
                System.out.println("Caught an ClientException, which means the client encountered "
                        + "a serious internal problem while trying to communicate with OSS, "
                        + "such as not being able to access the network.");
                System.out.println("Error Message:" + ce.getMessage());
            } finally {
//            if (ossClient != null) {
//                ossClient.shutdown();
//            }
            }
        }
    }


    /**
     * 网络流分片上传
     *
     * @param fileUrl           网络文件路径 https://www.xxx.com/xxx.mp4
     * @param fileSize          网络文件大小 5074989
     * @param filenameExtension 网络文件后缀类型mp4
     * @param objectName        填写Object完整路径，例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
     */
    /*public void inputStreamUploadPart(
            String accessKeyId, String accessKeySecret, String bucketName, String fileUrl, long fileSize, String filenameExtension, String objectName
    ) {
        OSS oss = null;
        try {
            // 填写Bucket所在地域。以华东1（杭州）为例，Region填写为cn-hangzhou。
            String region = "cn-shanghai";

            String contentType = getContentType(filenameExtension);

            com.aliyun.credentials.models.Config config = new com.aliyun.credentials.models.Config();
            // 访问凭证类型。固定为ram_role_arn
            config.setType("ram_role_arn");
            // 要扮演的RAM角色ARN，示例值：acs:ram::123456789012****:role/adminrole，可以通过环境变量ALIBABA_CLOUD_ROLE_ARN设置RoleArn
            config.setRoleArn(roleArn);
            // 从环境变量中获取AccessKeyId
            config.setAccessKeyId(accessKeyId);
            // 从环境变量中获取AccessKeySecret
            config.setAccessKeySecret(accessKeySecret);
            // 角色会话名称，可以通过环境变量ALIBABA_CLOUD_ROLE_SESSION_NAME设置RoleSessionName
            config.setRoleName(roleName);
            // 设置更小的权限策略，非必填。示例值：{"Statement": [{"Action": ["*"],"Effect": "Allow","Resource": ["*"]}],"Version":"1"}
//        config.setPolicy("<Policy>");
            // 设置角色会话有效期，非必填
            config.setRoleSessionExpiration(3600);

            final com.aliyun.credentials.Client credentialsClient = new com.aliyun.credentials.Client(config);

            CredentialsProvider credentialsProvider = new CredentialsProvider() {
                @Override
                public void setCredentials(Credentials credentials) {
                }

                @Override
                public Credentials getCredentials() {
                    CredentialModel credential = credentialsClient.getCredential();
                    return new DefaultCredentials(credential.getAccessKeyId(), credential.getAccessKeySecret(), credential.getSecurityToken());
                }
            };

            // 使用credentialsProvider初始化客户端
            ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
            // 显式声明使用 V4 签名算法
            clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
            // 创建OSSClient实例。
            // 当OSSClient实例不再使用时，调用shutdown方法以释放资源。
            oss = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .credentialsProvider(credentialsProvider)
                    .clientConfiguration(clientBuilderConfiguration)
                    .region(region)
                    .build();

            // 创建InitiateMultipartUploadRequest对象。
            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName);

            ObjectMetadata metadata = new ObjectMetadata();
            if (metadata.getContentType() == null) {
                metadata.setContentType(contentType);
            }
            request.setObjectMetadata(metadata);

            // 初始化分片上传，返回uploadId。
            InitiateMultipartUploadResult uploadResult = oss.initiateMultipartUpload(request);
            String uploadId = uploadResult.getUploadId();

            // partETags是PartETag的集合。
            List<PartETag> partETags = new ArrayList<>();

            // 计算文件分片数量。
            final long partSize = 5 * 1024 * 1024L; // 每个分片大小为5MB。

            // 遍历分片并上传。
            try (InputStream instream = new URL(fileUrl).openStream()) {
                byte[] buffer = new byte[8192]; // 设置缓冲区
                long remaining = fileSize;
                int partNumber = 1;

                while (remaining > 0) {
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    long bytesToRead = Math.min(partSize, remaining);

                    int bytesRead;
                    long totalRead = 0;
                    while (totalRead < bytesToRead && (bytesRead = instream.read(buffer)) > 0) {
                        baos.write(buffer, 0, bytesRead);
                        totalRead += bytesRead;
                    }

                    // 构造分片流
                    InputStream partStream = new ByteArrayInputStream(baos.toByteArray());

                    UploadPartRequest uploadPartRequest = new UploadPartRequest();
                    uploadPartRequest.setBucketName(bucketName);
                    uploadPartRequest.setKey(objectName);
                    uploadPartRequest.setUploadId(uploadId);
                    uploadPartRequest.setInputStream(partStream);
                    uploadPartRequest.setPartSize(totalRead);
                    uploadPartRequest.setPartNumber(partNumber++);

                    // 分片上传
                    UploadPartResult uploadPartResult = oss.uploadPart(uploadPartRequest);
                    partETags.add(uploadPartResult.getPartETag());

                    remaining -= totalRead;
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

            // 创建CompleteMultipartUploadRequest对象。
            CompleteMultipartUploadRequest completeMultipartUploadRequest =
                    new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);

            // 完成分片上传。
            CompleteMultipartUploadResult completeMultipartUploadResult = oss.completeMultipartUpload(completeMultipartUploadRequest);
            System.out.println("上传成功，ETag：" + completeMultipartUploadResult.getETag());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
            throw new RuntimeException(oe);
        } catch (ClientException ce) {
            System.out.println("Caught a ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
            throw new RuntimeException(ce);
        } finally {
            // 关闭OSSClient。
            if (oss != null) {
                oss.shutdown();
            }
        }
    }
*/

}